import os
import json as complex_json
from urllib.parse import urljoin, quote
import aiohttp
from p_config import Config
import requests
import websockets
import asyncio
import logging.config

logging.config.fileConfig('logging.conf')

logger = logging.getLogger('test')


def get_params(params):
    return '&'.join(f'{key}={quote(value)}' for key, value in params.items())


def load_config():
    current_dir = os.path.dirname(os.path.abspath(__file__))
    test_config_file = os.environ.get('TEST_CONFIG', 'default.yaml')
    test_config_file = os.path.join(current_dir, test_config_file)
    config = Config(test_config_file)
    return config


config = load_config()
unit_id = config['UNIT.ID']


class MyException(Exception):
    def __init__(self, *args):
        self.args = args


class MyAssertionError(AssertionError):
    def __init__(self, *args):
        self.args = args


class APISDK:
    def __init__(self, config=None, user_num=50):
        config = config or load_config()
        protocol = config['API_SERVER.HTTP_PROTOCOL']
        self.php_api_admin_url = config['API_SERVER.PHP_API_ADMIN_URL']
        host = config['API_SERVER.HOST']
        self.base_url = f'{protocol}//{host}'
        self.session = requests.session()
        self.async_session = aiohttp.ClientSession()
        # self.http_session = aiohttp.ClientSession()
        self.client_id = 'ndmooc_admin_frontend'
        self.teacher_list = [dict(username='15933983339',
                                  password='lc15933983339'), ]
        self.teacher_list = []
        num = 15900000000
        for i in range(1, user_num):
            num += 1
            a = dict(username=str(num), password='a12345678')
            self.teacher_list.append(a)
        self.student_list = [
            dict(username='15933983337', password='a15933983337')]

    async def get_access_token(self, username, password, client_id):
        url = '/account/v1/users/login'
        url = urljoin(self.base_url, url)
        data = {
            'loginid': username,
            'password': password,
            'client_id': client_id,
            'response_type': 'token',  # 返回类型。支持：token、cookie
        }
        resp = await self.async_session.post(url, data=data)
        json_resp = resp.json()
        error_code = json_resp['errcode']
        assert error_code, f'invalid errcode: {error_code}'
        return json_resp['data']

    async def get_access_token_from_php(self, session, username, password):
        url = '/account/v1/users/login'
        url = urljoin(self.php_api_admin_url, url)
        data = {
            'loginid': username,
            'password': password,
            'client_id': self.client_id,
            'response_type': 'token',  # 返回类型。支持：token、cookie
        }
        resp = await session.post(url, data=data)
        json_resp = await resp.json()
        error_code = json_resp['errcode']
        assert error_code == 0, f'invalid errcode: {error_code}'
        return json_resp['data']

    async def save_token(self):
        async with aiohttp.ClientSession() as s:
            for tea in self.teacher_list:
                a = tea['username']
                b = tea['password']
                user_data = await self.get_access_token_from_php(session=s,
                                                                 username=a,
                                                                 password=b
                                                                 )
                tea['data'] = user_data
                print(f'-----{tea=}')


class BrokerSDK:
    def __init__(self, unit_id, params=None, config=None, **kwargs):
        config = config or load_config()
        protocol = config['ZHONGKONG_SERVER_CC.WS_PROTOCOL']
        host = config['ZHONGKONG_SERVER_CC.HOST']
        self.base_url = f'{protocol}//{host}'
        url = f'v2/ngx/center/units/{unit_id}'
        self.url = urljoin(self.base_url, url)
        self.url += '?' + get_params(params)
        self.websocket = None
        self.websocket_kwargs = kwargs
        logger.info(f'{self.url=}')
        logger.info(f'{self.websocket_kwargs=}')

    async def __aenter__(self):
        self.websocket = await websockets.connect(
            self.url,
            **self.websocket_kwargs,
        )
        return self

    async def __aexit__(self, exc_type, exc, trace_back):
        await self.websocket.close()


class TestParams:
    def __init__(self, token, uid, message_count=1, send_sleep=1):
        self.unit_id = unit_id
        self.token = token
        self.uid = uid
        self.MESSAGE_COUNT = message_count
        self.send_sleep = send_sleep  # s

    async def send_message(self, ws):
        # for index in range(self.MESSAGE_COUNT):
        while 1:
            try:
                # logger.info(f'----send_message--------')
                await ws.send(
                    complex_json.dumps(
                        {"act": "15", "from": f"{self.uid}:name",
                         "msg": {"c": f"{self.uid}大家好", "etag": "00b1c3d4"}}))
                await asyncio.sleep(self.send_sleep)
            except Exception as err:
                print(err)
                break

    async def receive_message(self, ws):
        while True:
            res = await ws.recv()
            json_res = complex_json.loads(res)
            # logger.info(f'--{self.uid}收到---{json_res}--{ws.message_count=}-----')
            if 'act' in json_res and json_res['act'] == '19':
                pass
            else:
                ws.message_count += 1

    async def talk_mock(self):
        params = {'token': self.token}
        async with BrokerSDK(self.unit_id, params=params,
                             ping_timeout=99999) as broker:
            ws = broker.websocket
            register_msg = {"act": "1",
                            "os": "4", "vi": "1", "hw": "1"}
            await ws.send(complex_json.dumps(register_msg))
            ws.message_count = 0
            ws.client_index = self.uid
            await asyncio.gather(self.send_message(ws),
                                 self.receive_message(ws))


async def main():
    message_count = 1  # 每个ws 发消息次数
    send_sleep = 0.1  # 每条消息间隔秒数
    user_num = 30  # 用户数，需提前创建账号
    api = APISDK(user_num=user_num)
    await api.save_token()
    tasks = []
    logger.info('---ws_start---')
    for i in api.teacher_list:
        # logger.info(f'---{i=}')
        token = i['data']['access_token']
        uid = i['data']['uid']
        tes = TestParams(token=token, uid=uid, message_count=message_count,
                         send_sleep=send_sleep)
        tasks.append(tes.talk_mock())
    await asyncio.gather(*tasks)


if __name__ == "__main__":
    logger.info('---start---')

    asyncio.run(main())
